package hust.rpc;

import hust.rpc.annotation.Service;
import hust.rpc.constants.Constants;
import hust.rpc.handler.MessageDecoder;
import hust.rpc.handler.MessageEncoder;
import hust.rpc.handler.RegistryHandler;
import hust.rpc.invoker.RemoteInvoker;
import hust.rpc.proxy.AllProxy;
import hust.rpc.proxy.Proxy;
import hust.rpc.utils.ServiceScanUtils;
import hust.rpc.utils.SingletonUtils;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.Set;

/**
 * 注册中心启动器
 */
@Slf4j
public class RegistryBootstrap {

    /**
     * 绑定服务
     *
     * @see hust.rpc.service.ProviderService
     * @see hust.rpc.service.ConsumerService
     * 本地服务: 消费者首次的全量<服务, 服务提供者>信息、提供者上下线信息维护
     * @see hust.rpc.service.ConsumerService
     * 远程服务: 通知消费者提供者节点上下线信息
     */
    public static void bindService() throws IOException, ClassNotFoundException {
        // 创建代理对象
        SingletonUtils.registerInstance(Proxy.class, AllProxy.class);
        // 扫描包获取@Service标注的类
        Set<Class<?>> services = ServiceScanUtils.scanService(Constants.BASE_SCAN_PACKAGE, (clazz) -> {
            Service annotation = clazz.getAnnotation(Service.class);
            // value必须为服务注册者
            return Constants.REGISTRY.equals(annotation.value());
        });
        // 初始化代理对象
        SingletonUtils.getInstance(Proxy.class).initProxy(services);
    }

    /**
     * 启动注册中心监听服务提供者和消费者
     *
     * @param localIp   本地监听ip
     * @param localPort 本地监听端口
     */
    public static void run(String localIp, int localPort) throws IOException, ClassNotFoundException {
        // 绑定服务
        bindService();
        // 初始化远端调用者
        SingletonUtils.getInstance(RemoteInvoker.class);

        // Netty公式
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    // 关闭TCP的默认开启的Nagle算法
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    // 开启TCP底层心跳机制
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    // 设置连接超时时间
                    .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                    .handler(new LoggingHandler())
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast(new MessageDecoder());
                            pipeline.addLast(new MessageEncoder());
                            pipeline.addLast(SingletonUtils.getInstance(RegistryHandler.class));
                        }
                    });
            ChannelFuture channelFuture = serverBootstrap.bind(localIp, localPort);
            log.info("注册中心启动成功~~~");
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            log.error("注册中心启动失败: ", e);
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
